package app.domain.server.util;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import app.domain.order.Order;
import app.domain.order.OrderQueue;
import app.domain.order.util.Side;
import app.domain.order.util.Ticket;
import app.domain.order.util.Type;
import app.domain.server.Server;
import app.domain.server.TcpServer;
import app.domain.util.Logger;
import app.domain.util.StockProtocol;

public class MessageParseSender {
	
	public static void newOrder(String clientId, String msg, MessageOutBox queue, OrderQueue orderQueue) {
		Pattern pattern = Pattern.compile(StockProtocol.NEW_ORDER_MATCHER);
		Matcher matcher = pattern.matcher(msg);
		StringBuffer sendBuf = new StringBuffer(StockProtocol.NEW_ORDER_INVALID_FIELDS);
		while(matcher.find()) {
			if(Integer.parseInt(matcher.group(6)) <= 0) {
				sendBuf.append(StockProtocol.REFERENCE);}
			if(!Ticket.isTicket(matcher.group(3))) {
				sendBuf.append(StockProtocol.TICKET);}
			if(!Type.isType(matcher.group(4))) {
				sendBuf.append(StockProtocol.TYPE);}
			if(!Side.isSide(matcher.group(5))) {
				sendBuf.append(StockProtocol.SIDE);}
			if(Integer.parseInt(matcher.group(6)) <= 0) {
				sendBuf.append(StockProtocol.AMOUNT);} 
			if(matcher.group(4).equals(Type.L.getType()) && Double.valueOf(matcher.group(7)) <= Order.DELTA) {
				sendBuf.append(StockProtocol.PRICE);}
			if(!sendBuf.toString().equals(StockProtocol.NEW_ORDER_INVALID_FIELDS)) {
				queue.add(sendBuf.toString());
			} else {
				Logger.logServerInfo(StockProtocol.CREATING_ORDER);
				orderQueue.add(Order.createNewOrder(clientId,Integer.parseInt(matcher.group(2)),
						Ticket.valueOf(matcher.group(3)), Type.valueOf(matcher.group(4)), 
						Side.valueOf(matcher.group(5)), Integer.parseInt(matcher.group(6)), 
						Double.valueOf(matcher.group(7))));
			}
		}
	}	
	
	public static void cancelOrder(String clientId, String msg, MessageOutBox queue, OrderQueue orderQueue) {
		Pattern pattern = Pattern.compile(StockProtocol.CANCEL_ORDER_MATCHER);
		Matcher matcher = pattern.matcher(msg);
		StringBuffer sendBuf = new StringBuffer(StockProtocol.CANCEL_ORDER_INVALID_FIELDS);
		while(matcher.find()) {
			if(Integer.parseInt(matcher.group(2)) < 0) {
				sendBuf.append(StockProtocol.REFERENCE);
			} else {
				Logger.logServerInfo(StockProtocol.CANCELING_ORDER);
				orderQueue.add(Order.createCancelOrder(clientId,Integer.parseInt(matcher.group(2))));
			}
		}
	}
	
	public static void farewell(Server server,String clientId) {
		server.getClients().remove(clientId);
		Logger.logServerInfo("client " + clientId + " said bye and gone");
		server.getOrderQueue().add(Order.createDeleteClientOrder(clientId));
		Thread.currentThread().interrupt();
	}
	
	public static String login(TcpServer ts, ObjectInputStream in, ObjectOutputStream out) throws ClassNotFoundException, IOException {
		String login = (String)in.readObject();
		Logger.logServerInfo(login);
		if(!login.matches(StockProtocol.LOGIN_MATCHER)) {
			ts.sendMessage(out,StockProtocol.LOGIN_INVALID_ERROR);
			return null;
		} else {
			final String clientId = login.split("login=")[1];
			if(ts.getServer().getClients().keySet().contains(clientId)) {
				ts.sendMessage(out,StockProtocol.LOGIN_DUPLICATE_ERROR);
				return null;
			} else {
				Logger.logServerInfo("New client " + clientId);
				ts.sendMessage(out,StockProtocol.LOGIN_OK);
				return clientId;
			}
		}
	}
	
	public static void clientMessage(Server server, String clientId, String msg) {
		MessageOutBox queue = server.getClients().get(clientId).getMessageOutBox();
		if(msg.matches(StockProtocol.HEARTBEAT_MATCHER)) {
			server.getClients().get(clientId).setAlive(true);
		} else if (msg.matches(StockProtocol.FAREWELL_MATCHER)) {
			farewell(server, clientId);
		} else if(msg.matches(StockProtocol.NEW_ORDER_MATCHER)) {
			newOrder(clientId, msg, queue, server.getOrderQueue());
		} else if(msg.matches(StockProtocol.CANCEL_ORDER_MATCHER)) {
			cancelOrder(clientId, msg, queue, server.getOrderQueue());
		} else {
			queue.add(StockProtocol.INVALID);
		}						
	}
}